package com.ccx.demo.business.user.service;

import com.ccx.demo.business.user.vo.Authority;
import com.ccx.demo.config.init.AuthorityConfig;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.PostConstruct;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <pre>
 * 权限服务
 *
 * @author 谢长春 2019/8/27
 */
@Slf4j
@Service
@Validated
@RequiredArgsConstructor
public class AuthorityService {
    private final AuthorityConfig config;

    // 展开树节点
    private static final List<Authority> LIST = Lists.newArrayList();

    @PostConstruct
    public void postConstruct() {
        LIST.addAll(recursion(config.getTree()));
    }

    /**
     * 递归展开树节点
     *
     * @param tree {@link List<Authority>}
     * @return {@link List<Authority>}
     */
    private static List<Authority> recursion(final List<Authority> tree) {
        final Set<Authority> list = new LinkedHashSet<>();
        tree.forEach(node -> {
            if (CollectionUtils.isNotEmpty(node.getNodes())) {
                list.addAll(recursion(node.getNodes()).stream().peek(item -> item.setParentCode(node.getCode())).collect(Collectors.toList()));
            }
            list.add(node);
        });
        return list.stream()
                .map(Authority::cloneObject)
                .peek(obj -> obj.setNodes(null))
                .collect(Collectors.toList());
    }

    /**
     * 递归展开树节点，checked = true 且子节点数量为空的父节点也排除
     *
     * @param tree {@link List<Authority>}
     * @return {@link List<Authority>}
     */
    private static List<Authority> recursionChecked(final List<Authority> tree) {
        final List<Authority> list = Lists.newArrayList();
        tree.forEach(node -> {
            if (CollectionUtils.isNotEmpty(node.getNodes())) {
                final Set<Authority> nodes = recursionChecked(node.getNodes()).stream()
                        .filter(Authority::isChecked)
                        .peek(item -> item.setParentCode(node.getCode()))
                        .collect(Collectors.toCollection(LinkedHashSet::new));
                if (!nodes.isEmpty()) {
                    node.setChecked(true);
                    list.add(node);
                    list.addAll(nodes);
                }
            } else if (node.isChecked()) {
                list.add(node);
            }
        });
        return list.stream()
                .map(Authority::cloneObject)
                .peek(obj -> obj.setNodes(null))
                .collect(Collectors.toList());
    }

    /**
     * 按指定权限指令代码,递归构造树
     *
     * @param tree  {@link List<Authority>}
     * @param codes {@link Set<String>}
     * @return {@link List<Authority>}
     */
    private static List<Authority> filterTree(final List<Authority> tree, final Set<String> codes) {
        return tree.stream()
                .map(node -> {
                    if (CollectionUtils.isNotEmpty(node.getNodes())) {
                        final List<Authority> nodes = filterTree(node.getNodes(), codes);
                        if (CollectionUtils.isNotEmpty(nodes)) {
                            final Authority authority = node.cloneObject();
                            authority.setNodes(nodes);
                            return authority;
                        }
                        return null;
                    } else if (codes.contains(node.getCode())) {
                        return node;
                    }
                    return null;
                })
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }

    /**
     * 获取全部权限配置树集合
     *
     * @return {@link List<Authority>}
     */
    public List<Authority> getTree() {
        return config.getTree();
    }

    /**
     * 获取全部权限配置集合，树子节点展开
     *
     * @return {@link List<Authority>}
     */
    public List<Authority> getList() {
        return LIST;
    }

    /**
     * 展开指定的权限树
     *
     * @param tree {@link List<Authority>}
     * @return {@link List<Authority>}
     */
    public List<Authority> expendList(final List<Authority> tree) {
        return recursion(tree);
    }

    /**
     * 展开指定的权限树，且 checked 必须是选中状态
     *
     * @param tree {@link Set<Authority>}
     * @return {@link List<Authority>}
     */
    public List<Authority> expendFilterCheckedSet(final List<Authority> tree) {
        return recursionChecked(tree);
    }

    /**
     * 按权限指令代码获取权限树
     *
     * @param codes {@link Set<String>}
     * @return {@link List<Authority>}
     */
    public List<Authority> getTree(final Set<String> codes) {
        return filterTree(config.getTree(), codes);
    }

    /**
     * 按指定权限指令代码,递归构造树
     *
     * @param tree  {@link List<Authority>}
     * @param codes {@link Set<String>}
     * @return {@link List<Authority>}
     */
    private static List<Authority> filterTreeHidden(final List<Authority> tree, final Set<String> codes) {
        return tree.stream()
                .map(node -> {
                    if (node.isHidden() && !codes.contains(node.getCode())) { // 隐藏菜单且无权限
                        return null;
                    }
                    if (CollectionUtils.isNotEmpty(node.getNodes())) {
                        final List<Authority> nodes = filterTreeHidden(node.getNodes(), codes);
                        if (CollectionUtils.isNotEmpty(nodes)) {
                            final Authority authority = node.cloneObject();
                            authority.setNodes(nodes);
                            return authority;
                        }
                        return null;
                    }
                    return node;
                })
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }

    /**
     * 获取全部权限配置树集合，排除不在 codes 范围且状态为隐藏的权限
     *
     * @param codes {@link Set<String>}
     * @return {@link List<Authority>}
     */
    public List<Authority> getTreeCheckHidden(final Set<String> codes) {
        return filterTreeHidden(config.getTree(), codes);
    }

    /**
     * 获取全部权限配置集合，树子节点展开，排除不在 codes 范围且状态为隐藏的权限
     *
     * @param codes {@link Set<String>}
     * @return {@link List<Authority>}
     */
    public List<Authority> getListCheckHidden(final Set<String> codes) {
        return LIST.stream().filter(row -> {
            if (row.isHidden()) {
                return codes.contains(row.getCode());
            }
            return true;
        }).collect(Collectors.toList());
    }
//    public static void main(String[] args) {
//        System.out.println(JSON.toJSONString(TREE));
//        System.out.println(JSON.toJSONString(LIST));
//        final AuthorityService service = new AuthorityService();
//        System.out.println(JSON.toJSONString(service.getTree(Sets.newHashSet(role_list, Menu_Setting))));
//        System.out.println(JSON.toJSONString(service.getTree()));
//        System.out.println(new AuthorityService().expendFilterCheckedSet(
//                JSON.parseObject("[{\"ordinal\":1,\"code\":\"Menu_Manage_User\",\"name\":\"用户管理\",\"type\":\"MENU\",\"checked\":false,\"nodes\":[{\"ordinal\":3,\"code\":\"role_list\",\"name\":\"角色列表\",\"type\":\"MENU\",\"checked\":true}]}]", new TypeReference<Set<Authority>>(){})
//        ));
//    }
}
